//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package com.yang.sofa;

//import com.alipay.sofa.runtime.factory.BeanLoadCostBeanFactory;
//import com.alipay.sofa.runtime.log.SofaLogger;
//import com.alipay.sofa.runtime.spring.async.AsyncInitBeanHolder;
//import com.alipay.sofa.runtime.spring.async.AsyncTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.CountDownLatch;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.core.PriorityOrdered;

public class AsyncProxyBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware, InitializingBean, PriorityOrdered {
    private ApplicationContext applicationContext;
    private String moduleName;

    public AsyncProxyBeanPostProcessor() {
    }

    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        String methodName = AsyncInitBeanHolder.getAsyncInitMethodName(this.moduleName, beanName);
        if (methodName != null && methodName.length() != 0) {
            ProxyFactory proxyFactory = new ProxyFactory();
            proxyFactory.setTargetClass(bean.getClass());
            proxyFactory.setProxyTargetClass(true);
            AsyncProxyBeanPostProcessor.AsyncInitializeBeanMethodInvoker asyncInitializeBeanMethodInvoker = new AsyncProxyBeanPostProcessor.AsyncInitializeBeanMethodInvoker(bean, beanName, methodName);
            proxyFactory.addAdvice(asyncInitializeBeanMethodInvoker);
            return proxyFactory.getProxy();
        } else {
            return bean;
        }
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    public void afterPropertiesSet() {
        ConfigurableBeanFactory beanFactory = ((AbstractApplicationContext)this.applicationContext).getBeanFactory();
        if (beanFactory instanceof BeanLoadCostBeanFactory) {
            this.moduleName = ((BeanLoadCostBeanFactory)beanFactory).getId();
        } else {
            this.moduleName = "RootApplicationContext";
        }

    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Override
    public int getOrder() {
        return -2147483648;
    }

    class AsyncInitializeBeanMethodInvoker implements MethodInterceptor {
        private final Object targetObject;
        private final String asyncMethodName;
        private final String beanName;
        private final CountDownLatch initCountDownLatch = new CountDownLatch(1);
        private volatile boolean isAsyncCalling = false;
        private volatile boolean isAsyncCalled = false;

        AsyncInitializeBeanMethodInvoker(Object targetObject, String beanName, String methodName) {
            this.targetObject = targetObject;
            this.beanName = beanName;
            this.asyncMethodName = methodName;
        }

        public Object invoke(final MethodInvocation invocation) throws Throwable {
            if (AsyncTaskExecutor.isStarted()) {
                return invocation.getMethod().invoke(this.targetObject, invocation.getArguments());
            } else {
                Method method = invocation.getMethod();
                final String methodName = method.getName();
                if (!this.isAsyncCalled && methodName.equals(this.asyncMethodName)) {
                    this.isAsyncCalled = true;
                    this.isAsyncCalling = true;
                    AsyncTaskExecutor.submitTask(AsyncProxyBeanPostProcessor.this.applicationContext.getEnvironment(), new Runnable() {
                        public void run() {
                            try {
                                long startTime = System.currentTimeMillis();
                                invocation.getMethod().invoke(AsyncInitializeBeanMethodInvoker.this.targetObject, invocation.getArguments());
                                SofaLogger.info(String.format("%s(%s) %s method execute %dms, moduleName: %s.", AsyncInitializeBeanMethodInvoker.this.targetObject.getClass().getName(), AsyncInitializeBeanMethodInvoker.this.beanName, methodName, System.currentTimeMillis() - startTime, AsyncProxyBeanPostProcessor.this.moduleName));
                            } catch (Throwable var6) {
                                throw new RuntimeException(var6);
                            } finally {
                                AsyncInitializeBeanMethodInvoker.this.initCountDownLatch.countDown();
                                AsyncInitializeBeanMethodInvoker.this.isAsyncCalling = false;
                            }

                        }
                    });
                    return null;
                } else {
                    if (this.isAsyncCalling) {
                        long startTime = System.currentTimeMillis();
                        this.initCountDownLatch.await();
                        SofaLogger.info(String.format("%s(%s) %s method wait %dms, moduleName: %s.", this.targetObject.getClass().getName(), this.beanName, methodName, System.currentTimeMillis() - startTime, AsyncProxyBeanPostProcessor.this.moduleName));
                    }

                    return invocation.getMethod().invoke(this.targetObject, invocation.getArguments());
                }
            }
        }
    }
}
